home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
c_lib01.arc
/
LS.C
< prev
next >
Wrap
Text File
|
1985-10-16
|
16KB
|
524 lines
/*
NAME
dirc - UNIX-"ls" like directory listing utility written in 'C'.
Tested under PC-DOS using Lattice C rel 2.11.
This version allows limited recursive directory searches.
AUTHOR
Marty Ross, Computing Resource Center, Santa Monica, Ca.
For updates and more utilities of the like, call CRC-PC, or CRCBBS
bulletin board system(s). Currently at:
(213) 829-1487 (300 baud, IBM-PC)
(213) 828-1331 (300 baud, VM/370) <-- type "LOG DEMO DEMO" for access
NOTE: We are moving around late OCT., 1984 so above numbers will be
invalid after OCT, 1984.
SYNOPSIS
[pc/ms-dos]
A>dirc [-options] [d:][/path/]filename[.ext]
[as C function]
ret = dirc(s,op);
char *s; /* Pointer to [d:][/path/]filename[.ext] */
char *op; /* Pointer to option string */
/* Will 'ret' urn 0 normally, or 2 if no find */
where:
options
Is a string of lower case letters selecting
how many columns to generate, which files, according to
file attribute, should be displayed, and the selection
of file size/date of last access, volume header display,
subdirectory/time of creation, and file attribute bit
display. The option string "shrvdzt1" for instance,
will generate one column (1), will display system files
(s), hidden files (h), read-only files (r), volume-header
entry [files] (v), subdirectories (d), siZe (z), and
date-Time (t) information when it outputs its list.
An added feature in this version is the 'e' option, which
will also enable the 'd' option to show subdirectories
(which match the filename - usually '*.*'), and invoke
itself recursively for that subdirectory. Thus, an entire
hard-disk or other tree-structured file system can be
completely scanned with one command.
Note that because of DOS interfacing conventions, only
directories which match the file specification you typed
on the command line (if none, '*.*') will be shown. This
disables a potentially very useful feature: ability to
selectively scan across directories for particular files.
I will most likely include that feature in the next release
of DIRC, when I invent my own subroutines to handle wildcard
symbols myself - i'll always ask DOS for *.* and do the
filtering myself!
option letter meaning
-------------
1 Generate one column/line output.
2 Generate two columns/line output.
3 Generate three columns/line output.
4 Generate four colums/line output.
a Archive bit. Set on when file written
to since last FDISK backup. Allows DIRC to
select only files changed since last backup.
b Bits. Causes file access (mode) bits to be
displayed before each filename.
d Directories. Includes Subdirectories
in file searches.
e Expand. Expand sub-directories which match
given filename wildcard. Should use "*.*"
to get all subdirectories.
h Hidden files. List files with 'hidden' status.
l Long. Include '.' and '..' subdir files.
q Quiet. Don't say "[/path/]filesp:" before dir.
r Read-Only bit. Files which cannot be written to.
s System file. Don't erase these files.
t Time & Date. Include for each file.
u Un-archive bit. See files which have not been
changed since last FDISK BACKUP.
v Volume header(s?)
x Exclusive. Don't list "normal" files.
z siZe. Include for each file.
] Right Justify filenames in filename field.
[ Left Justfy filenames.
----------------
DESCRIPTION
DIRC provides a flexible directory interface to the PC-DOS
file system when using C under the Lattice compiler. Output goes
to STDOUT, and for this test version written as a PC-DOS command,
input is via the first two 'argv[]' tokens. Since it is a demonstration
of the capabilities of the DIRC function only, a simple option passing scheme
(using the second token), was chosen rather than the more standard
UNIX option scheme, where the option comes (optionally) first.
DIRC was written for PC-DOS using the Lattice C compiler. The
author claims to be no UNIX expert, but realizes that most of the features
of the program are 'boarrowed' from that system. The desired goal was a
flexible way to provide directories from within C programs. The first
result of that effort lies herein, in a test 'shell' which calls DIRC
using 'argv[1]' and 'argv[2]'.
From PC-DOS, you can specify both file specification and option
string as 'tokens', separating with a space. Because DIRC options are
lower case only (in the UNIX tradition), YOU MUST SPECIFY ALL OPTIONS
IN LOWER CASE!
Note that stack size is set large in case of deeply nested directories
when recursive option 'e' is used. If '*** STACK OVERFLOW ***' error STILL
occurs, then you may override the stack size, using the Lattice Compiler, by
typing an equal sign, followed by the desired stack size, in decimal.
I.E.:
A>dirc =30000 *.*
*/
int _stack = 25000; /* large stack in case of recursion! */
/* Following imitations of key routines in SEDIT.H */
int newline()
{
printf("\n");
return 0;
}
spout(line,arg1,arg2)
char *line;
int arg1, arg2;
{
printf("%s",line);
}
/* Start of DIRC.C */
#include <dos.h> /* Note: Tested under Lattice Rel 2.11 */
#define BLANK " " /* For SPOUT */
#define DEF_OPTS "" /* Use internal defaults now */
#define DEF_FN "*.*"
main(argc,argv)
int argc;
char *argv[];
{
int i, rc;
char *opts, *fn;
if (argc<2) {
opts = DEF_OPTS;
fn = DEF_FN;
}
else if (argv[1][0]=='-') {
if (argc<3) fn = DEF_FN;
else fn = argv[2];
opts = argv[1]; /* If options */
}
else {
opts = DEF_OPTS;
fn = argv[1];
}
rc=dirc(fn,opts);
if (rc && rc!=2) printf("R(%d);\n",rc);
}
#define FIND_FILE 0x4E /* DOS find file command */
#define NEXT_FILE 0x4F /* DOS next file command */
#define NORMAL_ATTR 0x20 /* "NORMAL" file attr */
#define DTA_SIZE 128 /* Size of DOS DTA */
#define B_F_WIDTH 13 /* 'vanilla' field width */
#define B_DIR_TYP 0 /* Default 'type' for DIR */
#define B_DIR_OPT 0x0B /* File and size only dflt */
#define K 1024 /* What is a 'K' ? */
#define NA 0 /* No Argument - don't care */
#define SET_DTA 0x1A /* Set DTA address DOS SVC */
char *filedate(), *filetime(); /* Forward references */
/* Our attribute byte fields */
#define F_RONLY 1 /* Read only bit */
#define F_HIDDEN 2 /* File hidden */
#define F_SYSTEM 4 /* System file */
#define F_VOLUME 8 /* Volume */
#define F_SUBDIR 16 /* Subdirectory */
#define F_ARCHIVE 32 /* Archived */
#define F_B6 64
#define F_B7 128
char fatbits[] = "rhsvda!?"; /* Meaning of attribute bits */
/* Our option bit flags image */
#define O_WIDTH 3 /* Two bit width field */
#define O_NONORMAL 4 /* Don't show normal files */
#define O_ONLYARCH 8 /* Only show archived files */
#define O_NOARCH 16 /* Only show non archived fls */
#define O_DATE 32 /* Include date/time */
#define O_SIZE 64 /* Show size of file */
#define O_ATTRIBS 128 /* Show file attribute bits */
#define O_QUIET 256 /* Quiet flag */
#define O_EXPAND 512 /* Expand sub-dirs */
#define O_RJUST 1024 /* Right- justify */
#define O_LONG 2048 /* Include '.' and '..' */
#define COLON ':'
#define ESCSYM '\\'
#define ESCSTR "\\"
/* k l u d g e macro (sorry) */
/* on if attrib selected */
#define L_Field (((options&O_ATTRIBS)?9:0)+f_width)
int mdirfile(fn,type,options)
char *fn;
char type;
unsigned options;
{
int nff;
int i, cp, rc;
int r_col, f_width;
char entr[81]; /* maximum length output tok */
char spbuf[10];
char temp[40];
char extbfr[128]; /* For rcrsv subdir expansion */
unsigned ds,dx, es, bx;
int dat,siz,attrs,rjust;
union { /* DTA and DIR field image */
char disk_buffer[DTA_SIZE];
struct {
char sys_data[21];
char file_attribute;
unsigned file_time ;
unsigned file_date ;
long file_size ;
char fn_ext[13] ;
} file_table;
} my_dta;
static int lvl; /* Level of recursion - will be zero when prog begins */
lvl++; /* First level */
rc = 1001; /* RC for no string given */
if (*fn != '\0') {
nff = 0; /* Zero files found so far */
f_width = B_F_WIDTH; /* Fieldsize for plain dir */
dat = (options & O_DATE);
siz = (options & O_SIZE); /* Size flag selected */
attrs = (options & O_ATTRIBS); /* Attributes required ? */
if (siz) f_width += 7; /* adjust 'per field' size */
if (dat) f_width += 16; /* etc...*/
r_col = ((options & O_WIDTH)+1)*L_Field;
rjust = (options & O_RJUST);
getdta(&ds,&dx); /* Get and save current DTA */
setdta(0,&my_dta); /* Set up our own DTA */
rc = bdos2(FIND_FILE,NA,NA,type,fn);
if (rc==0) { /* Look for ALL files */
while (rc==0) {
for (cp=0;cp<r_col&&rc==0;rc=bdos2(NEXT_FILE)) {
if (!(options&O_LONG)) {
if (!strcmp(my_dta.file_table.fn_ext,".") ||
!strcmp(my_dta.file_table.fn_ext,".."))
continue;
}
if (options&O_NONORMAL) { /* -x */
if (my_dta.file_table.file_attribute==NORMAL_ATTR)
continue;
}
if (options&O_ONLYARCH) { /* -a */
if (!(my_dta.file_table.file_attribute&F_ARCHIVE))
continue;
}
if (options&O_NOARCH) { /* -u */
if (my_dta.file_table.file_attribute&F_ARCHIVE)
continue;
}
if (nff++==0 && (options&O_QUIET)==0) {
sprintf(temp,"%s;\n",fn);
spout(temp,2,1);
}
if (attrs) { /* -b */
for (i=7;i>=0;i--) {
if (my_dta.file_table.file_attribute&(1<<i)) {
stccpy(spbuf,fatbits+i,2);
spout(spbuf,2,1);
}
else spout("-",2,1);
}
spout(BLANK,2,1);
}
if (rjust) sprintf(entr,"%12s",my_dta.file_table.fn_ext);
else sprintf(entr,"%-12s",my_dta.file_table.fn_ext);
if (siz) { /* -z */
if (my_dta.file_table.file_attribute &
F_VOLUME) sprintf(temp," <vol>");
else if (my_dta.file_table.file_attribute &
F_SUBDIR) sprintf(temp," <dir>");
else sprintf(temp,"%6.1fK",
(((float)my_dta.file_table.file_size / (float)K) + (float)0.05) );
strcat(entr,temp);
}
if (dat) { /* -t */
sprintf(temp," %s %s",
filedate(my_dta.file_table.file_date),
filetime(my_dta.file_table.file_time));
strcat(entr,temp);
}
i = f_width - strlen(entr) - 1;
while(i-->0) spout(BLANK,2,1);
spout(entr,2,1);
if ((my_dta.file_table.file_attribute&F_SUBDIR) && (options&O_EXPAND)
&& strcmp(my_dta.file_table.fn_ext,"..")
&& strcmp(my_dta.file_table.fn_ext,".")) {
spout("\n",2,1);
mknwdir(extbfr,fn,my_dta.file_table.fn_ext);
rc = mdirfile(extbfr,type,options);
cp = 0;
if (rc==1) break;
}
else {
cp+=L_Field; /* Account for horiz motion */
if (cp<r_col) {
spout(BLANK,2,1);
if (attrs || dat) spout(BLANK,2,1);
}
else if (newline()) {
rc=1;
break;
}
}
} /* End FOR */
if (rc==1) break;
} /* End WHILE */
} /* End IF */
setdta(ds,dx); /* Restore callers' DTA */
} /* endif */
if (nff==0) {
if (lvl==1) spout("No file(s) found.\n",2,1); /* 1st level only */
else {
if (!(options&O_NONORMAL)) {
sprintf(extbfr,"No files: %s\n",fn);
spout(extbfr,2,1);
}
}
rc = 2; /* No files found */
}
else {
if (rc==18) rc=0; /* Get rid of error 18 if files found */
if (cp && cp<r_col) spout("\n",2,1);
if (lvl!=1) {
sprintf(extbfr,"(End of %s)\n",fn);
spout(extbfr,2,1);
}
}
return rc;
} /* enddir */
int dirc(fn,optlist)
char *fn;
char *optlist;
{
unsigned opts; /* directory listing option bits */
char type; /* File attribute */
type = 0; /* Normal files only */
opts = 0; /* Default one column */
/* Default size & date/time */
/* if (!*optlist) opts = opts | O_SIZE | O_DATE; */
for (;*optlist;optlist++) {
switch(*optlist) {
case '-': ; /* Freedom of option passing */
break; case 'v': type = type | F_VOLUME; /* Volume headers req'd */
break; case 'r': type = type | F_RONLY; /* Read-only files */
break; case 'h': type = type | F_HIDDEN; /* Hidden files */
break; case 'd': type = type | F_SUBDIR; /* SubDirectories */
break; case 's': type = type | F_SYSTEM; /* System files */
break; case '!': type = type | F_B6; /* B6 ?? */
break; case '@': type = type | F_B7; /* B7 ?? */
break; case 'x': opts = opts | O_NONORMAL; /* Exclusive */
break; case 'a': opts = opts | O_ONLYARCH; /* Archived only */
type = type | F_ARCHIVE; /* Search for it, too */
break; case 'u': opts = opts | O_NOARCH; /* Un archived only */
type = ((~F_ARCHIVE)&type); /* Un-do the archive bit */
break; case 't': opts = opts | O_DATE; /* Show date/time */
break; case 'z': opts = opts | O_SIZE; /* Show size */
break; case 'b': opts = opts | O_ATTRIBS; /* Show attrib bits */
break; case 'q': opts = opts | O_QUIET; /* Shut up */
break; case 'e': opts = opts | O_EXPAND; /* Expand subdirs */
type = type | F_SUBDIR;
break; case 'l': opts = opts | O_LONG; /* Incl. '.' and '..' */
break; case ']': opts = opts | O_RJUST; /* Right justify fn's */
break; case '[': opts = opts & ~O_RJUST; /* Turn off RJUST */
break; case '1': ; /* number of columns */
case '2': ;
case '3': ;
case '4': opts = (opts&~(unsigned)3) | ((*optlist)-'1');
break; default: {
spout("Bad internal dir opts\n",2,1);
return 1;
}
}
}
if (*fn=='\0') fn="*.*"; /* Default for current version */
return (mdirfile(fn,type,opts));
}
mknwdir(buffer,curspec,newdir)
char buffer[], curspec[], newdir[];
{
char mybuf[32];
int i;
split_file(curspec,buffer,mybuf);
i = strlen(buffer);
if (i) {
if (buffer[--i]!=ESCSYM && buffer[i]!=COLON) strcat(buffer,ESCSTR);
}
strcat(buffer,newdir);
strcat(buffer,ESCSTR);
strcat(buffer,mybuf);
}
split_file(curspec,buffer,hisbuf)
char *curspec, *buffer, *hisbuf;
{
int i;
buffer[0] = hisbuf[0] = '\0';
i = strlen(curspec);
if (i) {
while(curspec[--i]!=ESCSYM && curspec[i]!=COLON && i!=0);
if (i) stccpy(buffer,curspec,++i+1);
strcpy(hisbuf,curspec+i);
}
}
char *filetime(codetime)
unsigned codetime;
{
static char ftime[7];
sprintf(ftime,"%02d:%02d",(codetime&0xF800)>>11,
(codetime&0x07E0)>>5);
return(ftime);
}
char *filedate(codedate)
unsigned codedate;
{
static char fdate[11];
sprintf(fdate,"%02d/%02d/%02d",
(codedate&0x01E0)>>5,
(codedate&0x001F),
((codedate&0xFE00)>>9)+80);
return(fdate);
}
#define GETDTA 0x2F
#define SETDTA 0x1A
/* (8) register = mdos(ah,al,bx,cx,dx) * Call DOS function (ah), pass parms */
bdos2(ah,al,bx,cx,dx)
char ah,al;
int bx,cx,dx;
{
union REGS myregs;
myregs.h.ah = ah;
myregs.h.al = al;
myregs.x.bx = bx;
myregs.x.cx = cx;
myregs.x.dx = dx;
intdos(&myregs,&myregs);
return myregs.x.ax;
}
getdta(esptr,bxptr)
unsigned *esptr,*bxptr;
{
union REGS myregs;
struct SREGS mysregs;
segread(&mysregs); /* Lattice suggests reading seg regs first */
myregs.h.ah = GETDTA;
intdosx(&myregs,&myregs,&mysregs);
*esptr = mysregs.es; /* Get DTA outputs to ES:BX */
*bxptr = myregs.x.bx;
}
setdta(es,bx)
unsigned es,bx;
{
union REGS myregs;
struct SREGS mysregs;
segread(&mysregs); /* Lattice suggests reading seg regs first */
myregs.h.ah = SETDTA; /* Assign new DTA function code */
myregs.x.dx = bx; /* Assign new offset to DTA */
if (es!=0) mysregs.ds = es; /* If zero, use our data segment */
intdosx(&myregs,&myregs,&mysregs); /* Set DTA req's DS:DX as argument */
}